#include "config.h"

#include <cstdio>
#include <iostream>
#include <string>

using namespace cfg;

// 函数: create_file
// 作用: 在当前工作目录创建指定文件并写入内容, 返回创建的文件路径; 若失败返回空字符串。
static std::string
create_file(const std::string & filename, const char * content)
{
    FILE * fp = std::fopen(filename.c_str(), "w");
    if (!fp)
        return {};
    std::fputs(content, fp);
    std::fclose(fp);
    return filename;
}

// 函数: print_error
// 作用: 结构化打印错误上下文, 便于观察触发自文件加载的典型错误。
static void
print_error(const ConfigError & e)
{
    std::cerr << "[" << static_cast<int>(e.code) << "] " << e.message;
    if (!e.path.empty())
    {
        std::cerr << " path=";
        for (size_t i = 0; i < e.path.size(); ++i)
        {
            if (i)
                std::cerr << ".";
            std::cerr << e.path[i];
        }
    }
    if (e.expected_type)
        std::cerr << " expected_type=" << static_cast<int>(*e.expected_type);
    if (e.actual_type)
        std::cerr << " actual_type=" << static_cast<int>(*e.actual_type);
    if (e.expected_pattern)
        std::cerr << " pattern=\"" << *e.expected_pattern << "\"";
    std::cerr << "\n";
}

// 函数: main
// 作用: 展示“文件触发”的错误, 包含: SchemaRootNotObject, IncludeOpenError, IncludeParseError。
int
main()
{
#ifndef CFG_ENABLE_YAML
    std::cerr << "CFG_ENABLE_YAML not enabled\n";
    return 1;
#else
    // 1) SchemaRootNotObject: 写入一个非对象根的 schema
    const std::string schema_not_obj = create_file("schema_root_not_object.yaml",
                                                   "- a\n- b\n"); // YAML 数组作为根

    // 2) IncludeOpenError: 直接 include 一个不存在的文件
    const std::string not_exist = "no_such_file_abcdef.yaml";

    // 3) IncludeParseError: 写入一个解析失败的文件
    const std::string parse_bad = create_file("syntax_bad.yaml", "key: [1, 2\n"); // 缺失右方括号

    // 3.1) SchemaRootNotObject 触发
    {
        Builder b;
        b.load_json_schema_file(schema_not_obj);
        auto fr = b.freeze();
        if (fr)
        {
            std::cout << "unexpected success for SchemaRootNotObject\n";
        }
        else
        {
            std::cout << "SchemaRootNotObject errors: " << fr.error().size() << "\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    // 3.2) IncludeOpenError 触发
    {
        Builder b;
        b.include_file(not_exist);
        auto fr = b.freeze();
        if (fr)
        {
            std::cout << "unexpected success for IncludeOpenError\n";
        }
        else
        {
            std::cout << "IncludeOpenError errors: " << fr.error().size() << "\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    // 3.3) IncludeParseError 触发
    {
        Builder b;
        b.include_file(parse_bad);
        auto fr = b.freeze();
        if (fr)
        {
            std::cout << "unexpected success for IncludeParseError\n";
        }
        else
        {
            std::cout << "IncludeParseError errors: " << fr.error().size() << "\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    // 4) 路径策略演示: 相对路径基于 base_dir 解析
    {
        // 构造一个目录结构: ./base_dir/inner.yaml
        // 注意: 这里用最小化方式, 将 base_dir 设为当前工作目录, 仅演示 API 行为
        Builder b;
        b.set_include_path_mode(IncludePathMode::RelativeToBaseDir).set_include_base_dir(".");

        // 写入被 include 的文件, 使用相对路径仅文件名
        const std::string inner = create_file("inner.yaml", "a: 1\n");
        (void)inner; // 抑制未使用警告

        b.include_file("inner.yaml");
        auto fr = b.freeze();
        if (fr)
        {
            View v(*fr);
            auto a = v.lookup("a").and_then([](const View & sv) { return sv.get_int64(); });
            if (a)
                std::cout << "PathMode demo: a=" << *a << "\n";
            else
                std::cout << "PathMode demo: missing a\n";
        }
        else
        {
            std::cout << "PathMode demo failed with errors: " << fr.error().size() << "\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    return 0;
#endif
}
